package BNS.kingPawn;

import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.event.*;
import javax.swing.*;
import BNS.graphs.*;

/** A class used for rendering a Graph during play.
	Kings and Pawns are shown in appropriate colors, and tips amounts are shown along the edges.
<p>	TODO: rename this (to KaPGraphPanel?)
	*/
public class ShowTipsPanel extends GraphPanel {
	
	static private final double wide=5.0;
	protected Polygon lustygon;
	protected EdgeState[] edgeStates;
	private NodeState[] nodeStates;
	
	/** Constructs a class by remembering where its data arrays are.
		@param ns an array of NodeState, giving running data about each Node in the Graph.
		@param es an array of EdgeState, giving running data about each Edge in the Graph.
		*/
	public ShowTipsPanel(NodeState[] ns, EdgeState[] es) { 
		super(ColorMap.identity());
		nodeStates= ns;
//		edgeStates= new EdgeState[0];
		edgeStates= es; 
		lustygon= new Polygon();	// for highlighting edges
		for (int i=0; i<5; i++) lustygon.addPoint(0,0);
		}
	
	/** Initializes the superclass GraphPanel, passing the Graph argument. */
	// TODO: Is this formally superfluous?
	public void init(Graph gr) { super.init(gr); }
	
	/** Paints a node, given a nodeState and a ColorMap.
		It is rendered as a circle of radius nodeRadius centered at the layout position of the Node.
		Its color depends on nodeState.winStatus; pawns are drawn using swatch[pawnInt],
		kings are drawn in swatch[kingInt], but conflicted kings are drawn in swatch[hurtInt].
		Eigennodes are labeled with "you"; others are given "+" and the node's otherEdges.
		*/
	protected void paintNode(Graphics g, NodeState nodeState, ColorMap render) {
		Node n= graph.getNode(nodeState.index);
		Point pt= n.position();
		int w= 2*nodeRadius;	//fm.stringWidth(n.lbl) + 10;
		int h= 2*nodeRadius;	//fm.getHeight() + 4;
		int clr= nodeState.winStatus==0? MarketISGame.hurtInt : 
				(nodeState.winStatus==1? MarketISGame.pawnInt : MarketISGame.kingInt);
		g.setColor(swatches[clr].color);
		g.fillOval(pt.x-w/2, pt.y-h/2,  w, h);
		g.setColor(Color.black);
		g.drawOval(pt.x-w/2, pt.y-h/2,  w, h);
		if (!graph.partial())	// indicates master graph (for Monitor)
			g.drawString(n.lbl, pt.x-fontmetrics.stringWidth(n.lbl)/2, pt.y+halfChar);
		else					// this is a graphlet (for a player)
			if (n==graph.eigenNode)
				g.drawString("you", pt.x-10, pt.y+halfChar);
			else 
				g.drawString("+"+n.otherEdges, pt.x-10, pt.y+halfChar);
		}
	
	/** Paints the whole graph, including edges, tips, and nodes.
		If the Graph is not fully initialized, it does nothing.
		It initally draws on offgraphics, then calls commitImage to make it visible.
		*/
	public synchronized void paint(Graphics g) {
		if (!ready(g)) return;
		drawEdges();
		doEdgeStates();
		drawNodes();	// This conceals parts of edges and tip arrows, so must happen last.
		commitImage(g);
		}
	
	/** Paints every node in nodeStates[] onto offgraphics. */
	public void drawNodes() {
		for (int i=0; i<nodeStates.length; i++) {
			NodeState nodeState= nodeStates[i];
//			Node n= graph.getNode(nodeState.index);
//			System.err.print(" "+n.color);
			paintNode(offgraphics, nodeState, render);
//			System.err.print(" "+nodeState.winStatus);
			}
//		System.err.println("  <== colors");
//		System.err.println("  <== winStati");
		}
	
	/** Paints an arrow at frNode along the edge toward toNode.
		The arrow's length is proportional to tip. 
		If filled is true then the arrow is painted in with the current color;
		otherwise it is left as an outline.
		*/
	private void paintLust(Graphics g, Node frNode, Node toNode, double tip, boolean filled) {
		Point to= toNode.position(), from= frNode.position();
		synchronized(lustygon) {
			double runx= (to.x-from.x), rise= (to.y-from.y);
			double angle= Math.atan2(rise,runx);
			double sin= Math.sin(angle), cos= Math.cos(angle);
			double dist= nodeRadius + tip*50;
//			System.err.println("paintLust dist "+dist);
			lustygon.xpoints[0]= (int)(from.x             + wide*sin);
			lustygon.ypoints[0]= (int)(from.y             - wide*cos);
			lustygon.xpoints[1]= (int)(from.x             - wide*sin);
			lustygon.ypoints[1]= (int)(from.y             + wide*cos);
			lustygon.xpoints[2]= (int)(from.x + (dist-3)*cos - wide*sin);
			lustygon.ypoints[2]= (int)(from.y + (dist-3)*sin + wide*cos);
			lustygon.xpoints[3]= (int)(from.x + (dist+2)*cos);
			lustygon.ypoints[3]= (int)(from.y + (dist+2)*sin);
			lustygon.xpoints[4]= (int)(from.x + (dist-3)*cos + wide*sin);
			lustygon.ypoints[4]= (int)(from.y + (dist-3)*sin - wide*cos);
			if (filled) g.fillPolygon(lustygon);
			else g.drawPolygon(lustygon);
			}
		}
	
	/** Considers each edge in edgeStates[] and draws the tips going in both directions
		in the color red. 
		*/
	protected void doEdgeStates() {
		offgraphics.setColor(Color.red);
		for (int i=0; i<edgeStates.length; i++) {
			drawTip(edgeStates[i].frIdx,edgeStates[i].toIdx,edgeStates[i].frTip);
			drawTip(edgeStates[i].toIdx,edgeStates[i].frIdx,edgeStates[i].toTip);
			}
		offgraphics.setColor(Color.black);
		}
	
	/** If this is the master graph, or if it is a graphlet and the designated edge involves
		the eigennode, then this method paints an arrow at the "from" node (indexed by frIdx)
		along the edge toward the "to" node (indexed by toIdx). If this graph is a graphlet and 
		the edge does not involve the eigennode, nothing is drawn. 
		The arrow's length is proportional to tip. 
		
		<p>If the "from" node is a King and is not currenly conflicted then the arrow is filled
		in with the current color; otherwise it is left as an outline.
		*/
	private void drawTip(int frIdx, int toIdx, float tip) {
		Node frN= graph.getNode(frIdx), toN= graph.getNode(toIdx);
		boolean filled= frN.color==MarketISGame.kingInt && nodeStates[frIdx].fights==-1;
		Point to= toN.position(), fr= frN.position();
		double angle= Math.atan2(to.y-fr.y,to.x-fr.x);
		double x= fr.x + (nodeRadius+25)*Math.cos(angle)-10;
		double y= fr.y + (nodeRadius+25)*Math.sin(angle)+halfChar;
		if (!graph.partial() || frIdx==graph.eigenNode.getIndex()) 
			paintLust(offgraphics,frN,toN,tip,filled); 
//		String show= String.format("%3.2f", tip);
//		offgraphics.drawString(show,(int)x,(int)y);
		}
	
	}
